import platgo as pg
import numpy as np


class CF4(pg.Problem):

    def __init__(self, D: int = 10):
        super().__init__()
        self.name = "CF4"
        self.type['multi'], self.type['real'], self.type['large'], self.type['constrained'] = [True] * 4
        self.M = 2
        self.D = D
        lb = [0] + [-2] * (self.D - 1)
        ub = [1] + [2] * (self.D - 1)
        self.borders = np.array([lb, ub])

    def cal_obj(self, pop: pg.Population) -> None:
        j1 = np.arange(2, self.D, 2)
        j2 = np.arange(1, self.D, 2)
        y = pop.decs - np.sin(6 * np.pi * pop.decs[:, 0].reshape(-1, 1) + np.arange(1, self.D + 1) * np.pi / self.D)
        h = y ** 2
        temp = y[:, 1] < 3/2*(1-np.sqrt(1/2))
        h[temp, 1] = np.abs(y[temp, 1])
        h[~temp, 1] = 0.125 + (y[~temp, 1] - 1) ** 2
        objv1 = pop.decs[:, 0] + np.sum(h[:, j1], axis=1)
        objv2 = 1 - pop.decs[:, 0] + np.sum(h[:, j2], axis=1)
        pop.objv = np.array([objv1, objv2]).T

    def cal_cv(self, pop: pg.Population) -> None:
        t = pop.objv[:, 1] - np.sin(6*np.pi*pop.objv[:, 0]+2*np.pi/self.M) - 0.5*pop.objv[:, 0] + 0.24
        pop.cv = (-t/(1+np.exp(4*np.abs(t)))).reshape(-1, 1)

    def get_optimal(self) -> np.ndarray:
        raise NotImplemented("get optimal has not been implemented")
